出处:掘金
原作者:ErpanOmer
WeakRef 与 FinalizationRegistry 是 JavaScript 中用于与垃圾回收器(GC)协同工作的两个高级 API,它们不干预 GC 行为,但允许我们在 GC 发生之后获取“副作用”的钩子。本质上,它们的触发并非实时,而是受 GC 策略支配、时间不确定、不可预测的“异步响应机制”
let obj = { name: "hello" };
let ref = new WeakRef(obj);
obj = null;
let derefValue = ref.deref(); // 有可能返回对象,也有可能已被 GC 回收后返回 undefined
GC 触发条件:
obj 必须处于不可达状态(Unreachable),即程序中不再有任何强引用注意:
.deref() 获取对象后,如果此时 GC 没有清除它,你可以继续操作.deref() 返回始终有效对象,因为它可能随时失效const registry = new FinalizationRegistry((heldValue) => {
console.log('对象被回收:', heldValue);
});
let obj = { foo: "bar" };
registry.register(obj, "my-object");
obj = null; // 此后某个时间,GC 会清理 obj,并异步调用注册函数
GC 触发条件:
heldValue 不是目标对象,而是你设置的“替身值”,用于说明“哪个对象”被清除特别强调:
V8 引擎(Chrome 和 Node.js 使用)中的 GC 策略具有多级触发机制:
WeakRef 和 FinalizationRegistry 都不影响 GC 是否执行,它们的工作依赖于:
因为:
const ref = new WeakRef(obj);
if (ref.deref()) {
// 认为 obj 还活着?错!它可能刚好 GC 还没动手!
}
这不是“活着”的判断方法。它只是“此刻 GC 可能还没动手”
const cache = new Map();
function getData(id) {
const ref = cache.get(id);
const val = ref?.deref();
if (val) return val;
const newVal = loadData(id);
cache.set(id, new WeakRef(newVal));
return newVal;
}
当数据被垃圾回收,WeakRef 会自动无效,下一次访问时重新加载
| 特性 | WeakRef | FinalizationRegistry |
|---|---|---|
| 是否影响 GC | 否(不会阻止对象被 GC) | 否(对象仍会被正常 GC) |
| GC 触发条件 | 目标对象无强引用且被 GC 回收 | 同上 |
| 是否保证触发 | 不保证 | 不保证 |
| 回调是否同步 | 无回调 | 异步回调 |
| 应用场景 | 缓存、软引用 | 清理副资源、日志、释放钩子等 |
| 是否能判断对象“还活着” | 否 | 否 |
WeakRef 与 FinalizationRegistry 是为应对现代复杂内存生命周期而生的工具。它们并不是让你掌控垃圾回收,而是允许你“在对象死亡之后做点事”
使用时需牢记两个原则:
结论: